package com.uvnos4j.matilda.system.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.uvnos4j.matilda.commons.config.properties.SysProperties;
import com.uvnos4j.matilda.commons.dto.PageParam;
import com.uvnos4j.matilda.commons.dto.QueryParam;
import com.uvnos4j.matilda.commons.exception.ServiceException;
import com.uvnos4j.matilda.commons.utils.MpUtil;
import com.uvnos4j.matilda.commons.utils.UserUtil;
import com.uvnos4j.matilda.system.domain.SysUser;
import com.uvnos4j.matilda.system.domain.SysUserRole;
import com.uvnos4j.matilda.system.error.SystemError;
import com.uvnos4j.matilda.system.mapper.SysUserMapper;
import com.uvnos4j.matilda.system.mapper.SysUserRoleMapper;
import com.uvnos4j.matilda.system.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * 用户 Service 实现
 * <p>
 * Description:用户 Service 实现
 * </p>
 *
 * @author Guo.wl
 * @version v1.0.0
 * @see com.uvnos4j.matilda.system.service.impl
 * @since 2020-08-31 23:29:47
 */
@Service
@Transactional(readOnly = true)
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    @Autowired(required = false)
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysProperties sysProperties;


    /**
     * 获取当前登录用户信息
     *
     * @return 当前登录用户信息
     */
    @Override
    public SysUser getUserInfo() {
        String username = UserUtil.getUsername();
        LambdaQueryWrapper<SysUser> lwq = new LambdaQueryWrapper<>();
        lwq.eq(SysUser::getUsername, username);
        return baseMapper.selectOne(lwq);
    }

    /**
     * 添加
     *
     * @param sysUser user
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SysUser sysUser) {
        if (hasSameUsername(sysUser.getUsername(), null)) {
            throw new ServiceException(SystemError.USER_NAME_REPEAT);
        }
        if (hasSameEmail(sysUser.getEmail(), null)) {
            throw new ServiceException(SystemError.USER_EMAIL_REPEAT);
        }
        String password = sysProperties.getUserInitPassword();
        if (passwordEncoder != null) {
            password = passwordEncoder.encode(sysProperties.getUserInitPassword());
        }
        sysUser.setPassword(password);
        sysUser.setCreateTime(DateUtil.date());
        sysUser.setEditPassTime(DateUtil.offsetDay(DateTime.now(), sysProperties.getUserPassValidDays()));
        int affectedRows = baseMapper.insert(sysUser);
        return affectedRows > 0;
    }

    /**
     * 根据Id修改
     *
     * @param sysUser user
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(SysUser sysUser) {
        if (hasSameUsername(sysUser.getUsername(), sysUser.getId())) {
            throw new ServiceException(SystemError.USER_NAME_REPEAT);
        }
        if (hasSameEmail(sysUser.getEmail(), sysUser.getId())) {
            throw new ServiceException(SystemError.USER_EMAIL_REPEAT);
        }
        int affectedRows = baseMapper.updateById(sysUser);
        return affectedRows > 0;
    }

    /**
     * 根据id删除
     *
     * @param userIdList idList
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> userIdList) {
        // 批量删除用户角色关系
        LambdaQueryWrapper<SysUserRole> lqw = new LambdaQueryWrapper<>();
        lqw.in(SysUserRole::getUserId, userIdList);
        sysUserRoleMapper.delete(lqw);

        // 批量删除用户
        int affectedRows = baseMapper.deleteBatchIds(userIdList);
        return affectedRows > 0;
    }

    @Override
    public IPage<SysUser> findPage(QueryParam param, PageParam pageParam, String orderBy) {
        System.out.println(sysProperties);
        String id = param.getStringValue("id");
        String username = param.getStringValue("username");
        String email = param.getStringValue("email");
        String deptId = param.getStringValue("deptId");
        String status = param.getStringValue("status");

        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(StrUtil.isNotBlank(id), SysUser::getId, id);
        lqw.like(StrUtil.isNotBlank(username), SysUser::getUsername, username);
        lqw.eq(StrUtil.isNotBlank(email), SysUser::getEmail, email);
        lqw.eq(StrUtil.isNotBlank(deptId), SysUser::getDeptId, deptId);
        // 数字传入字符转也可以可以自动处理
        lqw.eq(StrUtil.isNotBlank(status), SysUser::getStatus, status);

        Page<SysUser> page = new Page<>(pageParam.getPageNum(), pageParam.getPageSize());
        page.setOrders(MpUtil.getOrderList(orderBy));

        return baseMapper.selectPage(page, lqw);
    }

    @Override
    public void export(QueryParam param, PageParam pageParam, String orderBy, String fileDest) {
        IPage<SysUser> pageResult = findPage(param, pageParam, orderBy);

        ExcelWriter writer = ExcelUtil.getWriter(fileDest);
        // 自定义标题别名
        writer.addHeaderAlias("username", "用户名");
        writer.addHeaderAlias("nickName", "昵称");
        writer.addHeaderAlias("email", "电子邮箱");
        writer.addHeaderAlias("status", "状态");
        writer.addHeaderAlias("createTime", "创建时间");
        writer.addHeaderAlias("updateTime", "修改时间");

        writer.write(pageResult.getRecords(), true);
        writer.close();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resetPassword(List<Long> idList) {
        String encode = passwordEncoder.encode(sysProperties.getUserInitPassword());
        SysUser user = new SysUser();
        user.setPassword(encode);
        user.setEditPassTime(DateUtil.offsetDay(DateTime.now(), sysProperties.getUserPassValidDays()));

        LambdaQueryWrapper<SysUser> updateLqw = new LambdaQueryWrapper<>();
        updateLqw.in(SysUser::getId, idList);
        int updateRows = baseMapper.update(user, updateLqw);
        return updateRows > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePassword(String password, String newPassword) {
        SysUser userInfo = getUserInfo();
        if (!passwordEncoder.matches(password, userInfo.getPassword())) {
            throw new ServiceException(SystemError.USER_PASS_ERROR);
        }
        String encodePass = passwordEncoder.encode(newPassword);
        userInfo.setPassword(encodePass);
        userInfo.setEditPassTime(DateUtil.offsetDay(DateTime.now(), sysProperties.getUserPassValidDays()));
        int affectedRows = baseMapper.updateById(userInfo);

        return affectedRows > 0;
    }

    @Override
    public int countByDeptId(Long deptId) {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysUser::getDeptId, deptId);
        return baseMapper.selectCount(lqw);
    }

    /**
     * 新增或修改时校验是否有同名用户
     *
     * @param username 用户名称
     * @param userId   用户id，修改时用于排除自身
     * @return true含有同名用户；false不含同名用户
     */
    private boolean hasSameUsername(String username, Long userId) {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysUser::getUsername, username);
        lqw.ne(userId != null, SysUser::getId, userId);
        return baseMapper.selectCount(lqw) > 0;
    }

    /**
     * 新增或修改时校验是否有同邮箱用户
     *
     * @param email  用户名称
     * @param userId 用户id，修改时用于排除自身
     * @return true含有同邮箱用户；false不含同邮箱用户
     */
    private boolean hasSameEmail(String email, Long userId) {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysUser::getEmail, email);
        lqw.ne(userId != null, SysUser::getId, userId);
        return baseMapper.selectCount(lqw) > 0;
    }

    @Override
    public List<SysUser> findByRoleId(Long roleId) {
        return baseMapper.findByRoleId(roleId);
    }

    @Override
    public List<SysUser> findByAclId(Long aclId) {
        return baseMapper.findByAclId(aclId);
    }
}

